package org.springblade.upgrade.upload.controller;

import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.api.R;
import org.springblade.upgrade.upload.vo.FilePojoVo;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;


@Slf4j
@RestController()
@RequestMapping("/upload2")
public class Upload2Controller {

    /**
     * 合并
     *
     * @param filePojo
     * @return
     * @throws Exception
     */
    @PostMapping("/big-merge")
    public R<String> bigMerge(@RequestBody FilePojoVo filePojo) throws Exception {
        try {
            merge(filePojo.getFileName(), filePojo.getShardTotal(), filePojo.getKey());
            log.info("文件 {} 合并完成", filePojo.getFileName());
            return R.data("success");
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error("文件分片 {} 保存失败", ex.getMessage(), ex);
            return R.fail(ex.getMessage());
        }
    }

    /**
     * 大文件上传
     *
     * @param file
     * @param filePojo
     * @return
     * @throws Exception
     */
    @PostMapping("/big-upload")
    public R<String> bigUpload(@RequestParam(value = "file") MultipartFile file, FilePojoVo filePojo) throws Exception {
        try {
            bigUpload(filePojo.getFileName(), file, filePojo.getKey(), filePojo.getShardIndex(), filePojo.getShardTotal());
            log.info("文件分片 {} 保存完成", filePojo.getShardIndex());
            return R.data("success");
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error("文件分片 {} 保存失败", ex.getMessage(), ex);
            return R.fail(ex.getMessage());
        }
    }

    /**
     * 大文件分片上传
     *
     * @param fileName   文件名
     * @param file       文件
     * @param fileKey    文件key
     * @param shardIndex 当前分片下标
     * @param shardTotal 分片总量
     */
    private   void bigUpload(String fileName, MultipartFile file, String fileKey, Long shardIndex, Long shardTotal) throws Exception {
        String fileDir = "d:/upload/" + fileKey;
        File dir = new File(fileDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File dest = new File(fileDir + "/" + fileKey + "." + shardIndex);
        // 分片文件保存到文件目录
        file.transferTo(dest);
    }

    /**
     * 分片大文件上传，文件合并
     *
     * @param fileName   文件名比如123.mp4
     * @param shardTotal 分片总量
     * @param fileKey    文件key
     * @throws Exception
     */
    private   void merge(String fileName, Long shardTotal, String fileKey) throws Exception {
        //分片
        List<File> fileList = new ArrayList<>();
        File tempFile;
        String shardFilePath;
        for (int i = 0; i < shardTotal; i++) {
            // 读取第i个分片
            shardFilePath = "d:/upload/" + fileKey + "/" + fileKey + "." + (i + 1);
            tempFile = new File(shardFilePath);
            if (!tempFile.exists()) {
                throw new Exception("缺少分片，" + (i + 1));
            }
            if (tempFile.length() == 0) {
                throw new Exception("缺少分片，" + (i + 1));
            }
            fileList.add(tempFile);
        }

        String mergeFilePath = "d:/upload/" + fileKey + "/" + fileName;
        File newFile = new File(mergeFilePath);
        if (newFile.exists()) {
            newFile.delete();
        }
        FileOutputStream outputStream = new FileOutputStream(newFile, true);//文件追加写入
        FileInputStream fileInputStream = null;//分片文件
        byte[] byt = new byte[10 * 1024 * 1024];
        int len;
        try {
            for (File file : fileList) {
                // 读取第i个分片 );
                fileInputStream = new FileInputStream(file);
                while ((len = fileInputStream.read(byt)) != -1) {
                    outputStream.write(byt, 0, len);//一直追加到合并的新文件中
                }
            }
        } finally {
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
                outputStream.close();
                System.gc();
            } catch (Exception e) {
            }
        }
        for (File file : fileList) {
            file.deleteOnExit();
        }

    }
}
